package com.sxyjhh.schedule;


import com.sxyjhh.utils.common.RegexpValidate;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.springframework.scheduling.concurrent.ConcurrentTaskScheduler;
import org.springframework.scheduling.support.CronTrigger;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.*;

/**
 * Description:定时任务管理
 *
 * @JDK Version:1.8.0_40
 * Version: V1.0
 * Author: spring
 * Date: 2016/5/4
 */
@Component
public class TaskSchedulerManager {
    /**
     * logger日志.
     */
    private static final Logger log = Logger.getLogger(TaskSchedulerManager.class);
    private static Map<String, TaskRunnable> TASKS = new HashMap();
    private static Map<String, ScheduledFuture<?>> SCHEDULED_FUTURE = new HashMap();

    private final static int POOL_SIZE = 128;

    private final ConcurrentTaskScheduler ct = new ConcurrentTaskScheduler(Executors.newScheduledThreadPool(POOL_SIZE));

    /**
     * 启动一个计划任务.
     *
     * @param task 当前进行的任务.
     */
    public void start(TaskRunnable task) throws Exception {
        try {
            if (StringUtils.isEmpty(task.getTaskId())) {
                throw new Exception("任务id不能为空.");
            }

            if (StringUtils.isEmpty(task.getTrigger())) {
                throw new Exception("任务的调度表达式不能为空.");
            }

            if (!RegexpValidate.checkCronExpression(task.getTrigger())) {
                throw new Exception("任务的调度表达式格式错误.");
            }

            ScheduledFuture<?> scheduledFuture = ct.schedule(task, new CronTrigger(task.getTrigger()));
            SCHEDULED_FUTURE.put(task.getTaskId(), scheduledFuture);
            TASKS.put(task.getTaskId(), task);
            log.info("任务id=" + task.getTaskId() + "已经启动成功.");
        } catch (Exception e) {
            log.info(e.toString());
            throw e;
        }
    }

    /**
     * 停止一个计划任务.
     *
     * @param taskId 任务编号.
     */
    public void stop(String taskId) throws Exception {
        try {
            ScheduledFuture<?> scheduledFuture = null;
            if (isRunning(taskId)) {
                scheduledFuture = SCHEDULED_FUTURE.remove(taskId);
                if (scheduledFuture != null && !scheduledFuture.isCancelled()) {
                    /** false 表示当前任务若正在执行，则待其执行结束，再结束此任务. */
                    scheduledFuture.cancel(true);
//                throw new Exception("任务id=" + taskId + "不存在.");
                }
            }
            if (TASKS.containsKey(taskId)) {
                TASKS.remove(taskId);
            }
        } catch (Exception e) {
            log.info(null, e);
            throw e;
        }
    }

    /**
     * 重新设置当前任务的执行频率.
     *
     * @param taskId 任务编号.
     */
    public void resetTrigger(String taskId, String cronExpression) throws Exception {
        log.info("正在修改当前任务 " + taskId + "执行频率.");
        if (StringUtils.isEmpty(taskId)) {
            throw new Exception("任务id不能为空.");
        }

        if (StringUtils.isEmpty(cronExpression)) {
            throw new Exception("任务的调度表达式不能为空.");
        }

        if (!RegexpValidate.checkCronExpression(cronExpression)) {
            throw new Exception("任务的调度表达式格式错误.");
        }


        TaskRunnable task = TASKS.get(taskId);
        if (task != null) {
            if (cronExpression.equals(task.getTrigger())) {
                return;
            }
            /** first, stop the task. */
            ScheduledFuture<?> scheduledFuture = SCHEDULED_FUTURE.remove(taskId);
            scheduledFuture.cancel(false);

            /** second, reset the task with cronExpression. */
            task.setTrigger(cronExpression);
            /** third, restart the task. */
            scheduledFuture = ct.schedule(task, new CronTrigger(cronExpression));
            SCHEDULED_FUTURE.put(taskId, scheduledFuture);
        }
    }

    /**
     * 仅执行一次.
     *
     * @param task 所要执行任务.
     */
    public void onlyOneTime(TaskRunnable task) throws Exception {
        if (StringUtils.isEmpty(task.getTaskId())) {
            throw new Exception("任务id不能为空.");
        }
        ct.execute(task, 0);
    }

    /**
     * 销毁线程池中的任务.
     */
    public void destrory() {
        log.info("正在终止自动任务的线程池资源.");
        ScheduledExecutorService scheduledExecutor = (ScheduledExecutorService) ct.getConcurrentExecutor();
        try {
            scheduledExecutor.shutdownNow();
        } catch (Exception e) {
            log.info("自动任务的线程池资源清理发生异常.", e);
        } finally {
            log.info("自动任务的线程池资源清理完成.");
        }
    }

    public boolean isRunning(String taskId) {
        return SCHEDULED_FUTURE.containsKey(taskId);
    }

}
